import { combineReducers, createSlice, configureStore } from '@reduxjs/toolkit'
import logger from 'redux-logger'
import _ from 'lodash'
import { valid } from '@/utils'
import { isAntdTable, getInitState, formatTablePagination, formatUpdateKeys } from './tools'

const { isValidObject } = valid

let uid = 0

let prefix = ''

let slices = {}

let store = null

let rootReducer = combineReducers({})

const init = (system) => {
  if (!system) {
    throw new Error('store --- init: please enter system name')
  }
  prefix = system
  store = configureStore({
    reducer: rootReducer,
    // TODO: 只在开发环境中生效
    middleware: (m) => m().concat(logger)
  })
  return store
}

const create = (state = {}, reducers = {}) => {
  if (!store) {
    throw new Error('store --- create: please init the store')
  }

  const key = `__${prefix}__${uid++}__`

  if (slices[key]) {
    throw new Error('store --- create: store name conflict')
  }

  const { reducer, actions } = createSlice({
    name: key,
    initialState: state,
    reducers: reducers
  })

  Object.assign(slices, {
    [key]: reducer
  })


  store.replaceReducer(combineReducers(slices))

  return {
    name: key,
    actions
  }
}


const processor = (state = {}, reducers = {}, config) => {
  const newState = {
    ...getInitState(config),
    ...state
  }
  const newReducers = {
    // 注入更新
    update: (state, params) => {
      const { payload } = params || {}
      const keys = isValidObject(payload) ? Object.keys(payload) : []
      keys.forEach((key) => {
        state[key] = payload[key]
      })
    },
    ...reducers
  }

  const { name, actions } = create(newState, newReducers)

  const result = {}

  if (isValidObject(config)) {
    const { caller, items } = config || {}
    for (let i = 0, len = items.length; i < len; i++) {
      const item = items[i] || {}
      if (isAntdTable(item)) {
        const newName = item.callee || item.name
        result[newName] = (params, success, fail) => async (dispatch, getState) => {
          console.log('获取 state ----- ', getState())
          // 返回处理好的 antd table 需要的数据格式
          const initState = {
            [newName]: {
              loading: true,
              pagination: { current: params?.current, pageSize: params?.pageSize, total: 0 },
              list: []
            }
          }
          typeof actions.update === 'function' && dispatch(actions.update(initState))
          try {
            const query = {
              ..._.omit(params, ['current', 'pageSize']),
              offset: Math.max(params.current - 1, 0) * params.pageSize,
              limit: params.pageSize
            }
            const res = await (item.caller || caller)[item.callee || item.key](query)
            // 返回处理好的 antd table 需要的数据格式
            const updateState = {
              [newName]: {
                loading: false,
                list: Array.isArray(res?.data) ? res?.data : [],
                pagination: formatTablePagination(res?.pagination)
              }
            }
            typeof actions.update === 'function' && dispatch(actions.update(updateState))
            // 返回未经处理的接口数据，支持用户自定义处理
            typeof success === 'function' && success(res)
          } catch (err) {
            typeof fail === 'function' && fail(err)
          }
        }
        continue
      }
      const hasAction = !!actions[item.action] || !!item.updateKeys
      result[item.name] = (params, success, fail) => async dispatch => {
        try {
          const res = await (item.caller || caller)[item.callee || item.key](params)
          if (hasAction) {
            // action 优先
            if (item.action && typeof actions[item.action] === 'function') {
              dispatch(actions[item.action](res))
            } else if (item.updateKeys) {
              // 其次判断 updateKeys
              const params = formatUpdateKeys(item.updateKeys, res)
              dispatch(actions.update(params))
            }
          }
          typeof success === 'function' && success(res)
        } catch (err) {
          typeof fail === 'function' && fail(err)
        }
      }
    }
  }

  return {
    name,
    actions: actions,
    requests: result
  }
}

export {
  store,
  init,
  processor
}